package com.hyacinth.dubbo.io.netty.server;

import com.hyacinth.dubbo.io.netty.codec.PacketCodecHandler;
import com.hyacinth.dubbo.io.netty.codec.PacketDecoder;
import com.hyacinth.dubbo.io.netty.codec.PacketEncoder;
import com.hyacinth.dubbo.io.netty.codec.Spliter;
import com.hyacinth.dubbo.io.netty.monitor.IMIdleStateHandler;
import com.hyacinth.dubbo.io.netty.server.handler.*;
import com.hyacinth.dubbo.io.netty.util.SessionUtil;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;

import java.util.Date;

/**
 * netty服务端
 * @author zhangfb
 * @version 1.0.0.1
 * @since JDK 1.8
 */
public class NettyServer {

    private static final int PORT = 8080;

    public static void main(String[] args) {
        // 表示监听端口，accept新连接的线程组
        NioEventLoopGroup bossGroup = new NioEventLoopGroup();
        // 处理每一条连接的数据读写的线程组
        NioEventLoopGroup workGroup = new NioEventLoopGroup();

        // 创建server端引导程序
        ServerBootstrap bootstrap = new ServerBootstrap();
        bootstrap
                // 1.指定线程模型
                .group(bossGroup, workGroup)
                // 2.指定 IO 类型为 NIO
                .channel(NioServerSocketChannel.class)
                // 设置相关属性
                // 系统用于临时存放已完成三次握手的请求的队列的最大长度，
                // 如果连接建立频繁，服务器处理创建新连接较慢，可以适当调大这个参数
                .option(ChannelOption.SO_BACKLOG, 2048)
                // 表示是否开启TCP底层心跳机制，true为开启
                .childOption(ChannelOption.SO_KEEPALIVE, true)
                // 是否开启Nagle算法，true表示关闭，false表示开启，
                // 通俗地说，如果要求高实时性，有数据发送时就马上发送，就关闭，
                // 如果需要减少发送次数减少网络交互，就开启
                .childOption(ChannelOption.TCP_NODELAY, true)
                // 3.IO 处理逻辑
                .childHandler(new ChannelInitializer<NioSocketChannel>() {
                    @Override
                    protected void initChannel(NioSocketChannel ch) throws Exception {
                        // 空闲检测
                        ch.pipeline().addLast(new IMIdleStateHandler());
                        ch.pipeline().addLast(new Spliter());
                        ch.pipeline().addLast(PacketCodecHandler.INSTANCE);
                        ch.pipeline().addLast(LoginRequestHandler.INSTANCE);
                        ch.pipeline().addLast(HeartBeatRequestHandler.INSTANCE);
                        ch.pipeline().addLast(AuthHandler.INSTANCE);
                        ch.pipeline().addLast(IMHandler.INSTANCE);
                    }
                });
        // 绑定端口
        bind(bootstrap, PORT);
    }

    /**
     * 递增绑定端口
     */
    private static void bind(final ServerBootstrap serverBootstrap, final int port) {
        serverBootstrap.bind(port).addListener(future -> {
            if (future.isSuccess()) {
                System.out.println(new Date() + ": 端口[" + port + "]绑定成功!");
            } else {
                System.err.println("端口[" + port + "]绑定失败!");
            }
        });
    }
}
